home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / memory / drivers / drivers.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1995-04-10  |  32.3 KB  |  1,317 lines

  1. UNIT Drivers;
  2.  
  3. {
  4.   DRIVERS.PAS - Version 1.00 - By R.A.J. van Eeghem, (C) 1995
  5.  
  6.   date        : April, 1995
  7.   contents    : mouse-driver, EMS-driver (3.0), XMS-driver (3.0)
  8.   language    : Borland/Turbo Pascal 6.0 (or higher)
  9.   autor        : R.A.J. van Eeghem, Netherlands
  10.   e-mail    : ruud@tnk.phys.tue.nl
  11. }
  12.  
  13. {
  14.   Copyright/Permissions:
  15.  
  16.   You are allowed to use this any or all parts of this code for youre own
  17.   benefits, provided you do not modify it and/or sell it. Furthermore I'd
  18.   appreciate it if you put my name into youre credits-list.
  19.  
  20.   Disclaimer:
  21.  
  22.   Note that I'll not take responsibility for any damage caused by using
  23.   this code. It's the users sole responsibility to test this code for his
  24.   or her purposes.
  25.  
  26.   Credits:
  27.  
  28.   My thanks goes to the people of Borland for designing the language
  29.   Borland/Turbo Pascal.
  30. }
  31.  
  32. {
  33.   Mouse Driver:
  34.  
  35.   The mouse driver provides a set of API-routines to communicate with a
  36.   mousedriver, loaded at startup. To use them, the user must first call
  37.   InitMouse. This procedure will initialize some of the global variable.
  38.   The user can then check the global boolean MouseAvail to see wether a
  39.   mouse is available. After using the mouse-driver, driver will be reset
  40.   to it's original state.
  41.  
  42.   routine        what it does
  43.  
  44.   InitMouse        initializes the mouse driver API
  45.   DoneMouse        deinitializes the mouse driver API
  46.  
  47.   ShowMouse        make mouse pointer visible
  48.   HideMouse        make mouse pointer hidden
  49.   LocateMouse        locate mouse pointer a position (x,y)
  50.  
  51.   GetMouseInfo        get current status of mouse
  52.   GetMousePressInfo    get button press information
  53.   GetMouseReleaseInfo    get button release information
  54.  
  55.   SetLimits        limit area of mouse pointer
  56.   SetGraphPointer    set alternate mouse pointer (graphics mode only)
  57.  
  58.   SetUserEventHandler    set user-defined event handler
  59.   SwapUserEventHandler    swap user-defined event handler
  60. }
  61.  
  62. {
  63.   EMS Driver:
  64.  
  65.   The EMS-driver provides acces to most of the LIM-EMS 3.0 API-functions.
  66.   To use the EMS-driver, the user simply calls InitEMS wich will check
  67.   for the existence of a EMS-driver. If a driver is available, it will
  68.   set EMSAvail to TRUE. The user must then request the version number and
  69.   check wether it is above 3.0 (this is usually true since EMS 4.0 dates
  70.   1987 and by now all EMS-drivers are full 4.0 compliant). However only
  71.   the 3.0 functions actually deal with allocating and freeing memory (up
  72.   to 64 kB), wich is the usual stuff people want to do with it.
  73.  
  74.   Some internals about the use of EMS. To allocate memory, you simply
  75.   call AllocEMS specifying the amount of kB you need. The memory can only
  76.   be allocated in pages of 16 kB so we specify the number of pages instead
  77.   of the actual memory in kB. As a result of the allocation we get a handle,
  78.   wich is simply a 16-bit number identifying youre memory block (something
  79.   like a pointer - but you cannot use it to acces memory directly).
  80.  
  81.   To acces the memory obtained we must first map the EMS-memory onto the
  82.   physical accessible swaparea. This is done by MapEMS. Since the segment
  83.   is 64 kB this means we can map 4 pages of EMS-memory (note: this does not
  84.   mean the 4 pages of memory all have to belong to the same handle, we can
  85.   map 4 pages of 4 different handles together in the swap-area, as long as
  86.   they are physically separated).
  87.  
  88.   After using the memory we free it by calling FreeEMS. After that the
  89.   handle becomes invalid and can no longer be used. Now one important thing:
  90.   the EMS-driver is an external driver. So if you allocate memory but don't
  91.   release it this memory will stay allocated until you reboot youre com-
  92.   puter. This in contrast to DOS-memory (below 640 kB). This means that
  93.   you'll need a critical errorhandler that releases all EMS before ter-
  94.   minating youre program!!
  95.  
  96.   routine        what it does
  97.  
  98.   InitEMS        checks for the existence of an EMS-driver
  99.   EMSGetVersion        returns version number of EMS-driver
  100.  
  101.   AllocEMS        allocates EMS-memory
  102.   FreeEMS        frees allocated EMS-memory
  103.   MapEMS        map's EMS into the DOS-accessible swap-area
  104.  
  105.   EMSGetFreePages    returns number of free pages available
  106.   EMSGetHandlePages    returns number of allocated pages of a handle
  107. }
  108.  
  109. {
  110.   XMS Driver:
  111.  
  112.   The XMS Driver provides acces to a subset of the XMS 3.0 API-functions.
  113.   To use this routine the user must first call InitXMS. This will set
  114.   XMSAvail to TRUE if an XMS-driver is found. After that the user must
  115.   verify that the XMS-driver is of version 3.0 or above.
  116.  
  117.   To allocate XMS the user can simply call AllocXMS. The XMS-driver will
  118.   then return a handle wich from now on will identify the allocated memory
  119.   (like a pointer - however it cannot be used to acces memory directly).
  120.  
  121.   To use the XMS-memory, the user can rely on RealToXMS for swapping data
  122.   from real memory (below 640 kB) to XMS-memory and XMSToReal for the
  123.   reverse process. An additional routine is provided for swapping from
  124.   XMS->XMS (MoveXMS) however in real-mode programs (= normal DOS programs)
  125.   this routine will hardly be of any use.
  126.  
  127.   After using the memory, the XMS-handle (and the XMS-memory belonging to
  128.   it) should be freed by calling FreeXMS. On other option is to expand/
  129.   reduce the size of the XMS-memory using ReAllocXMS. However, one special
  130.   note must be added to this: the XMS-driver is an external program, so
  131.   if you end youre program without releasing all used XMS-memory, the
  132.   memory will be kept allocated (until you reboot youre computer). This
  133.   means that you'll need a critical errorhandler that releases all XMS
  134.   before terminating youre program!!
  135.  
  136.   routine        what it does
  137.  
  138.   InitXMS        checks for the existence of a XMS-driver
  139.   XMSGetVersion        returns version number of the XMS-driver
  140.  
  141.   AllocXMS        allocates XMS-memory
  142.   FreeXMS        frees allocated XMS-memory
  143.   MoveXMS           moves XMS-memory around in XMS-memory
  144.   ReAllocXMS        resizes the amount of XMS-memoyr for a given handle
  145.  
  146.   RealToXMS        swaps real-memory to XMS-memory
  147.   XMSToReal        swaps XMS-memoyr to real-memory
  148. }
  149.  
  150. INTERFACE
  151.  
  152. {
  153.   ------------------------------------------------------------------------
  154.  
  155.         Declaration Mouse Driver
  156.  
  157.   ------------------------------------------------------------------------
  158. }
  159. CONST
  160.   mouseNoError        = 0;
  161.   mouseInsuffMemory    = 1;
  162.   mouseNoMouseFound    = 2;
  163.  
  164. CONST
  165.   mbLEFTBUTTON        = 1;
  166.   mbRIGHTBUTTON        = 2;
  167.   mbCENTERBUTTON    = 3;
  168.  
  169. CONST
  170.   maskMOUSE_MOVE    = 1;
  171.   maskLB_PRESSED     = 2;
  172.   maskLB_RELEASED    = 4;
  173.   maskRB_PRESSED    = 8;
  174.   maskRB_RELEASED    = 16;
  175.   maskCB_PRESSED    = 32;
  176.   maskCB_RELEASED    = 64;
  177.  
  178. CONST
  179.   MouseAvail        :BOOLEAN=FALSE;
  180.  
  181. TYPE
  182.   MouseRecord        =RECORD
  183.     x,y,button,count    :WORD;
  184.   END;
  185.  
  186. TYPE
  187.   UserEventHandler    =RECORD
  188.     mask        :WORD;
  189.     handler        :POINTER;
  190.   END;
  191.  
  192. PROCEDURE    InitMouse;
  193. PROCEDURE    DoneMouse;
  194.  
  195. PROCEDURE    ShowMouse;
  196. PROCEDURE    HideMouse;
  197. PROCEDURE    LocateMouse(x,y:WORD);
  198.  
  199. FUNCTION    GetMouseInfo(VAR m:MouseRecord):WORD;
  200. FUNCTION    GetMousePressInfo(button:WORD; VAR m:MouseRecord):WORD;
  201. FUNCTION    GetMouseReleaseInfo(button:WORD; VAR m:MouseRecord):WORD;
  202.  
  203. PROCEDURE    SetLimits(xtop,ytop,xbottom,ybottom:WORD);
  204. PROCEDURE    SetGraphPointer(xhspot,yhspot:WORD; VAR imagebuffer);
  205.  
  206. PROCEDURE    SetUserEventHandler(VAR hUser:UserEventHandler);
  207. PROCEDURE    SwapUserEventHandler(VAR hUser:UserEventHandler);
  208.  
  209. {
  210.   ------------------------------------------------------------------------
  211.  
  212.         Declaration EMS Driver (EMS 3.0)
  213.  
  214.   ------------------------------------------------------------------------
  215. }
  216.  
  217. CONST
  218.   EMSAvail        :BOOLEAN=FALSE;
  219.   EMSErrorCode        :BYTE=0;
  220.   EMSPageFrameAdress    :POINTER=NIL;
  221.   EMSTotalPages        :WORD=0;
  222.   EMSFreePages        :WORD=0;
  223.  
  224. CONST
  225.   EMSerror_NoError            = $00;
  226.   EMSerror_EMSSoftwareInternalError     = $80;
  227.   EMSerror_HardwareMailfunction        = $81;
  228.   EMSerror_MemoryManagerBusy        = $82;
  229.   EMSerror_InvalidHandle        = $83;
  230.   EMSerror_FunctionNotDefined        = $84;
  231.   EMSerror_NoMoreHandlesAvailable    = $85;
  232.   EMSerror_MappingContextSaveLoadError    = $86;
  233.   EMSerror_RequestExceedsSystemLimits    = $87;
  234.   EMSerror_ReqeustExceedsFreeMemLimits    = $88;
  235.  
  236. PROCEDURE    InitEMS;
  237. PROCEDURE    EMSGetVersion(VAR num,dec:BYTE);
  238.  
  239. FUNCTION    AllocEMS(VAR handle:WORD; numpages:WORD):BOOLEAN;
  240. FUNCTION    FreeEMS(VAR handle:WORD):BOOLEAN;
  241. FUNCTION    MapEMS(srcPage:WORD; destPage:BYTE; VAR handle:WORD):BOOLEAN;
  242.  
  243. FUNCTION    EMSGetFreePages:WORD;
  244. FUNCTION    EMSGetHandlePages(VAR handle:WORD):WORD;
  245.  
  246. {
  247.   ------------------------------------------------------------------------
  248.  
  249.         Declaration XMS Driver (XMS 3.0)
  250.  
  251.   ------------------------------------------------------------------------
  252. }
  253.  
  254. CONST
  255.   XMSAvail        :BOOLEAN=FALSE;
  256.   XMSErrorCode        :BYTE=0;
  257.   XMSFreeMemory        :WORD=0;
  258.   XMSMaxBlock        :WORD=0;
  259.  
  260. CONST
  261.   XMSerror_NoError            = $00;
  262.   XMSerror_FunctionNotImplemented    = $80;
  263.   XMSerror_VirtualDiskDetected        = $81;
  264.   XMSerror_A20error            = $82;
  265.   XMSerror_GeneralDriverError        = $8E;
  266.   XMSerror_UnrecoverableDriverError    = $8F;
  267.   XMSerror_HMADoesNotExist        = $90;
  268.   XMSerror_HMAAlreadyInUse        = $91;
  269.   XMSerror_DXLessThanHMAMINParameter    = $92;
  270.   XMSerror_HMANotAllocated        = $93;
  271.   XMSerror_A20StillEnabled        = $94;
  272.   XMSerror_AllXMSAllocated        = $A0;
  273.   XMSerror_OutOfXMSHandles        = $A1;
  274.   XMSerror_InvalidHandle        = $A2;
  275.   XMSerror_SourceHandleInvalid        = $A3;
  276.   XMSerror_SourceOffsetInvalid        = $A4;
  277.   XMSerror_DestHandleInvalid        = $A5;
  278.   XMSerror_DestOffsetInvalid        = $A6;
  279.   XMSerror_LengthInvalid        = $A7;
  280.   XMSerror_MoveHasInvalidOverlap    = $A8;
  281.   XMSerror_ParityError            = $A9;
  282.   XMSerror_BlockIsNotLocked        = $AA;
  283.   XMSerror_BlockIsLocked        = $AB;
  284.   XMSerror_LockCountOverflow        = $AC;
  285.   XMSerror_LockFail            = $AD;
  286.   XMSerror_SmallerUMBAvailable        = $B0;
  287.   XMSerror_NoUMBAvailable        = $B1;
  288.   XMSerror_UMBSegmentNumberInvalid    = $B2;
  289.  
  290. TYPE
  291.   XMSMoveStruct        =RECORD
  292.     length        :LONGINT;
  293.     hSource        :WORD;
  294.     offsetSource    :LONGINT;
  295.     hDest        :WORD;
  296.     offsetDest        :LONGINT;
  297.   END;
  298.  
  299. PROCEDURE    InitXMS;
  300. PROCEDURE    XMSGetVersion(VAR num,dec:BYTE);
  301.  
  302. FUNCTION    AllocXMS(VAR handle:WORD; sizeKB:WORD):BOOLEAN;
  303. FUNCTION    FreeXMS(VAR handle:WORD):BOOLEAN;
  304. FUNCTION    MoveXMS(VAR mvData:XMSMoveStruct):BOOLEAN;
  305. FUNCTION    ReAllocXMS(VAR handle:WORD; newsizeKB:WORD):BOOLEAN;
  306.  
  307. FUNCTION    XMSGetMaxBlock:WORD;
  308. FUNCTION    XMSGetBlockSIze(VAR handle:WORD):WORD;
  309.  
  310. PROCEDURE    RealToXMS(VAR source; VAR hDest:WORD; ofs,cnt:LONGINT);
  311. PROCEDURE       XMSToReal(VAR hSource:WORD; ofs:LONGINT; VAR dest; cnt:LONGINT);
  312.  
  313. IMPLEMENTATION
  314.  
  315. USES Dos;
  316.  
  317. {
  318.   ------------------------------------------------------------------------
  319.  
  320.         Implementation Mouse Driver
  321.  
  322.   ------------------------------------------------------------------------
  323. }
  324. VAR
  325.   _savestatebuffer    :POINTER;
  326.   _savestatebuffersize    :WORD;
  327.   _numberbuttons    :WORD;
  328.   _errorcode        :WORD;
  329.  
  330. {
  331.   procedure    : InitMouse
  332.   parameters    : none
  333.   result    : none
  334.  
  335.   Saves the current state of the mouse driver and initializes the mouse-
  336.   driver again. This procedure will initialize the global variable
  337.   MouseAvail.
  338. }
  339. PROCEDURE InitMouse;
  340. VAR
  341.   r            :REGISTERS;
  342. BEGIN
  343.   _errorcode:=mouseNoError;
  344.  
  345.   { initialize no mouse available }
  346.   _savestatebuffersize:=0;
  347.   _savestatebuffer:=NIL;
  348.  
  349.   { get mouse save state buffer size }
  350.   r.ax:=$0015;
  351.   intr($33,r);
  352.  
  353.   { check if memory can be allocated }
  354.   IF ( maxavail<r.bx ) THEN
  355.   BEGIN
  356.     _errorcode:=mouseInsuffMemory; exit;
  357.   END;
  358.  
  359.   { allocate memory for buffer }
  360.   _savestatebuffersize:=r.bx;
  361.   getmem(_savestatebuffer,_savestatebuffersize);
  362.  
  363.   { save mouse driver status }
  364.   r.ax:=$0016;
  365.   r.dx:=ofs(_savestatebuffer^);
  366.   r.es:=seg(_savestatebuffer^);
  367.   intr($33,r);
  368.  
  369.   { initialize mouse }
  370.   r.ax:=$0000;
  371.   intr($33,r);
  372.  
  373.   { if no mouse available }
  374.   IF ( r.ax=$0000 ) THEN
  375.   BEGIN
  376.     _errorcode:=mouseNoMouseFound; exit;
  377.   END;
  378.  
  379.   { store number of mouse-buttons }
  380.   MouseAvail:=TRUE;
  381.   _numberbuttons:=r.bx;
  382. END;
  383.  
  384. {
  385.   procedure    : DoneMouse
  386.   parameters    : none
  387.   result    : none
  388.  
  389.   Deinitializes the mouse-driver by reloading the previous status of the
  390.   driver.
  391. }
  392. PROCEDURE DoneMouse;
  393. VAR
  394.   r            :REGISTERS;
  395. BEGIN
  396.   _errorcode:=mouseNoError;
  397.  
  398.   { check if previous status was saved }
  399.   IF ( _savestatebuffer<>NIL ) THEN
  400.   BEGIN
  401.  
  402.     { restore mouse driver status }
  403.     r.ax:=$0017;
  404.     r.dx:=ofs(_savestatebuffer^);
  405.     r.es:=seg(_savestatebuffer^);
  406.     intr($33,r);
  407.  
  408.     { release allocated memory }
  409.     freemem(_savestatebuffer,_savestatebuffersize);
  410.     _savestatebuffer:=NIL;
  411.   END;
  412. END;
  413.  
  414. {
  415.   procedure    : ShowMouse
  416.   parameters    : none
  417.   result    : none
  418.  
  419.   Increases the internal counter of the mouse-driver. If the count is above
  420.   zero, the mousepointer is visible.
  421. }
  422. PROCEDURE ShowMouse;ASSEMBLER;
  423. ASM
  424.     MOV    AX,0001h
  425.     INT    33h
  426. END;
  427.  
  428. {
  429.   procedure    : HideMouse
  430.   parameters    : none
  431.   result    : none
  432.  
  433.   Decreases the internal counter of the mouse-driver. If the count is below
  434.   or equal zero, the mousepointer will be hidden.
  435. }
  436. PROCEDURE HideMouse;ASSEMBLER;
  437. ASM
  438.     MOV    AX,0002h
  439.     INT    33h
  440. END;
  441.  
  442. {
  443.   procedure    : LocateMouse
  444.   parameters    : x,y:WORD
  445.   result    : none
  446.  
  447.   Locates the mouspointer at location (x,y) on the screen. The upper left
  448.   corner is given by (0,0) and the coordinates are measured in pixels.
  449. }
  450. PROCEDURE LocateMouse(x,y:WORD);ASSEMBLER;
  451. ASM
  452.     MOV    AX,0004h
  453.     MOV    CX,[x]
  454.     MOV    DX,[y]
  455.     INT    33h
  456. END;
  457.  
  458. {
  459.   function    : GetMouseInfo
  460.   parameters    : VAR m:MouseRecord
  461.   result    : WORD
  462.  
  463.   Request the current mouse position, button status and button count. The
  464.   data are stored in MouseRecord m. Returns the current status of the
  465.   buttons.
  466. }
  467. FUNCTION GetMouseInfo(VAR m:MouseRecord):WORD;ASSEMBLER;
  468. ASM
  469.     MOV    AX,0003h
  470.     INT    33h
  471.     LES    DI,m
  472.     MOV     MouseRecord[DI].x,CX
  473.     MOV    MouseRecord[DI].y,DX
  474.     MOV    MouseRecord[DI].count,01h
  475.     MOV    MouseRecord[DI].button,BX
  476.     MOV    AX,BX
  477. END;
  478.  
  479. {
  480.   function    : GetMousePressInfo
  481.   parameters    : button:WORD; VAR m:MouseRecord
  482.   result    : WORD
  483.  
  484.   Requests the current status of all mouse-buttons, the number of presses
  485.   and the position of the last press of the requested mouse button. The
  486.   information is stored in MouseRecord m. Returns the current status of
  487.   the mouse buttons.
  488. }
  489. FUNCTION GetMousePressInfo(button:WORD;VAR m:MouseRecord):WORD;ASSEMBLER;
  490. ASM
  491.     MOV    AX,0005h
  492.     MOV    BX,[button]
  493.     SHR    BX,1
  494.     INT    33h
  495.     LES    DI,m
  496.     MOV    MouseRecord[DI].button,AX
  497.     MOV    MouseRecord[DI].count,BX
  498.     MOV    MouseRecord[DI].x,CX
  499.     MOV    MouseRecord[DI].y,DX
  500. END;
  501.  
  502. {
  503.   function    : GetMouseReleaseInfo
  504.   parameters    : button:WORD; VAR m:MouseRecord
  505.   result    : WORD
  506.  
  507.   Requests the current status of all mouse-buttons, the number of releases
  508.   and the posiotion of the last release of the requested mouse button. The
  509.   information is stored in MouseRecord m. Returns the current status of
  510.   the mouse button.
  511. }
  512. FUNCTION GetMouseReleaseInfo(button:WORD; VAR m:MouseRecord):WORD;ASSEMBLER;
  513. ASM
  514.     MOV    AX,0006h
  515.     MOV    BX,[button]
  516.     SHR    BX,1
  517.     INT    33h
  518.     LES    DI,m
  519.     MOV    MouseRecord[DI].button,AX
  520.     MOV    MouseRecord[DI].count,BX
  521.     MOV    MouseRecord[DI].x,CX
  522.     MOV    MouseRecord[DI].y,DX
  523. END;
  524.  
  525. {
  526.   procedure    : SetLimits
  527.   parameters    : xtop,ytop,xbottom,ybottom:WORD
  528.   result    : none
  529.  
  530.   Limits the pointer display area to the rectangle given by (xtop,ytop)-
  531.   (xbottom,ybottom). Note that (0,0) is assumed to be de upper left corner
  532.   and that the coordinates are measured in pixels.
  533. }
  534. PROCEDURE SetLimits(xtop,ytop,xbottom,ybottom:WORD);ASSEMBLER;
  535. ASM
  536.     { set horizontal limits }
  537.     MOV    AX,0007h
  538.     MOV    CX,[xtop]
  539.     MOV    DX,[xbottom]
  540.     INT    33h
  541.     { set vertical limits }
  542.     MOV    AX,0008h
  543.     MOV    CX,[ytop]
  544.     MOV    DX,[ybottom]
  545.     INT    33h
  546. END;
  547.  
  548. {
  549.   procedure    : SetGraphPointer
  550.   parameters    : xhspot,yhspot:WORD; VAR imagebuffer
  551.   result    : none
  552.  
  553.   Defines a new pointer shape in graphics mode. The pointer shape is stored
  554.   in imagebuffer, a 64-byte buffer. The first 32-bytes contain a bit mask
  555.   that is ANDed with the screen image. The last 32-byte contain a bit mask
  556.   that is XORed with the screen image.
  557.  
  558.   The hot-spot is defined relative from the upper left corner of the mouse-
  559.   pointer image (coordinate (0,0) ) and measured in pixels. Each pixel-
  560.   offset must be within the range -16..16. In display modes 4 and 5 (320x200
  561.   graphics) the offset must be an even number.
  562. }
  563. PROCEDURE SetGraphPointer(xhspot,yhspot:WORD; VAR imagebuffer);ASSEMBLER;
  564. ASM
  565.     MOV    AX,0009h
  566.     MOV    BX,[xhspot]
  567.     MOV    CX,[yhspot]
  568.     MOV    DX,SEG imagebuffer
  569.     MOV    ES,DX
  570.     MOV    DX,OFFSET imagebuffer
  571.     INT    33h
  572. END;
  573.  
  574. {
  575.   procedure    : SetUserEventHandler
  576.   parameters    : VAR hUser:UserEventHandler
  577.   result    : none
  578.  
  579.   Installs a user-defined eventhandler. This is a function wich is called
  580.   whenever the state of the mouse complies to the given mask. Both handler-
  581.   function and mask are defined in the UserEventHandler-record.
  582.  
  583.   The bitmask is interpreted as follows:
  584.  
  585.   bit        significance (if set)
  586.  
  587.   0             mouse movement
  588.   1        left button pressed
  589.   2        left button released
  590.   3        right button pressed
  591.   4        right button released
  592.   5        center button pressed
  593.   6        center button released
  594.   7-15        reserved (0)
  595.  
  596.   The user-defined eventhandler is called as a normal far function with
  597.   the registers set up as follows.
  598.  
  599.   AX        mouse event flags
  600.   BX        button state (a mbXXXX-value)
  601.   CX        horizontal x-coordinate
  602.   DX        vertical y-coordinate
  603.   SI        last raw vertical mickey count
  604.   DI        last raw horizontal mickey count
  605.   DS        mouse driver datasegment
  606.  
  607.   Note that bits that do not generate a call to the user-defined event
  608.   handler are still reported in AX.
  609.  
  610.   One problem arising with a user-defined handler is to acces the global
  611.   data from within the handler-function. This can be done by the following
  612.   code.
  613.  
  614.     PUSH    DS
  615.     PUSH    AX
  616.  
  617.     MOV    AX,SEG identifier
  618.     MOV    DS,AX
  619.  
  620.     ...
  621.  
  622.     POP    AX
  623.     POP    DS
  624.  
  625.   Where identifier is the name of a global variable. Remember that youre
  626.   program can have different data-segments (eg. data of a unit are stored
  627.   in a different segment then data of the main source file).
  628. }
  629. PROCEDURE SetUserEventHandler(VAR hUser:UserEventHandler);ASSEMBLER;
  630. ASM
  631.     LES    DI,hUser
  632.     MOV    AX,WORD PTR UserEventHandler[DI+2].handler
  633.     MOV    DX,WORD PTR UserEventHandler[DI].handler
  634.     MOV    CX,WORD PTR UserEventHandler[DI].mask
  635.     MOV    ES,AX
  636.     MOV    AX,000Ch
  637.     INT    33h
  638. END;
  639.  
  640. {
  641.   procedure    : SwapUserEventHandler
  642.   parameters    : VAR hUser:UserEventHandler
  643.   result    : none
  644.  
  645.   Swaps the currently active user-eventhandler for a new user-eventhandler
  646.   defined in the UserEventHandler-record hUser. The old handler and its
  647.   mask will be returnd in hUser. For the description of user-eventhandlers
  648.   the user is referred to the procedure SetUserEventHandler.
  649.  
  650.   WARNING: contents of hUser is not preserved!
  651. }
  652. PROCEDURE SwapUserEventHandler(VAR hUser:UserEventHandler);ASSEMBLER;
  653. ASM
  654.     LES    DI,hUser
  655.     MOV    AX,WORD PTR UserEventHandler[DI+2].handler
  656.     MOV    DX,WORD PTR UserEventHandler[DI].handler
  657.     MOV    CX,WORD PTR UserEventHandler[DI].mask
  658.     MOV    ES,AX
  659.     MOV    AX,0014h
  660.     INT    33h
  661.  
  662.     MOV    AX,ES
  663.     LES    DI,hUser
  664.     MOV    WORD PTR UserEventHandler[DI+2].handler,AX
  665.     MOV    WORD PTR UserEventHandler[DI].handler,DX
  666.     MOV    WORD PTR UserEventHandler[DI].mask,CX
  667. END;
  668.  
  669. {
  670.   ------------------------------------------------------------------------
  671.  
  672.         Implementation EMS Driver (EMS 3.0)
  673.  
  674.   ------------------------------------------------------------------------
  675. }
  676.  
  677. CONST
  678.   EMSDriverName        :STRING[8]='EMMXXXX0';
  679.  
  680. {
  681.   procedure    : InitEMS
  682.   parameters    : none
  683.   result    : none
  684.  
  685.   Initializes the EMS API-functions. This is done by first establishing
  686.   the fact that EMS is available and setting the global boolean EMSAvail.
  687. }
  688. PROCEDURE InitEMS;ASSEMBLER;
  689. ASM
  690.     PUSH    DS
  691.  
  692.     { get adress of interrupt vector 67h }
  693.     MOV    AL,67h
  694.     MOV    AH,35h
  695.     INT    21h
  696.  
  697.     { ES:BX = handler adress }
  698.     { assume driver is loaded at ES:0000h }
  699.     { name driver is located at ES:000Ah }
  700.     MOV    DI,000Ah
  701.  
  702.     { load compare string and skip length byte }
  703.     LEA    SI,EMSDriverName
  704.     INC    SI
  705.  
  706.     { load count register }
  707.     MOV    CX,8
  708.     CLD
  709.     REP    CMPSB
  710.     JNZ    @Exit
  711.  
  712.     { check if driver and hardware is available }
  713.     MOV    AH,40h
  714.     INT    67h
  715.     MOV    [EMSErrorCode],AH
  716.     CMP    AH,00h
  717.     JNE    @Exit
  718.  
  719.     { get page frame adress }
  720.     MOV    AH,41h
  721.     INT    67h
  722.     MOV    [EMSErrorCode],AH
  723.     CMP    AH,00h
  724.     JNE    @Exit
  725.     MOV    WORD PTR [EMSPageFrameAdress+2],BX
  726.  
  727.     MOV    [EMSAvail],TRUE
  728.  
  729.     MOV    AH,42h
  730.     INT    67h
  731.     MOV    [EMSErrorCode],AH
  732.     CMP    AH,00h
  733.     JNE    @Exit
  734.     MOV    [EMSTotalPages],DX
  735.     MOV    [EMSFreePages],BX
  736.  
  737. @Exit:    POP    DS
  738. END;
  739.  
  740. {
  741.   procedure    : GetVersion
  742.   parameters    : VAR num,dec:BYTE
  743.   result    : none
  744.  
  745.   Returns the version of the EMS-driver. The integer part is returned in
  746.   num and the decimal part in dec.
  747. }
  748. PROCEDURE EMSGetVersion(VAR num,dec:BYTE);ASSEMBLER;
  749. ASM
  750.     { get version in BCD-code }
  751.     MOV    AH,46h
  752.     INT    67h
  753.     MOV    [EMSErrorCode],AH
  754.     CMP    AH,00h
  755.     JNE    @Exit
  756.     { copy version number }
  757.     MOV    AH,AL
  758.     { create decimal number in AL }
  759.     AND    AL,0Fh
  760.     { create integer number in AH }
  761.     AND    AH,0F0h
  762.     SHR    AH,4
  763.     { store result in parameters }
  764.     LES    DI,num
  765.     MOV    BYTE PTR [DI],AH
  766.     LES    DI,dec
  767.     MOV    BYTE PTR [DI],AL
  768.  
  769.     POP    BP
  770.     RET    TYPE num + TYPE dec
  771.  
  772. @Exit:  LES    DI,num
  773.     MOV    BYTE PTR [DI],00h
  774.     LES    DI,dec
  775.     MOV    BYTE PTR [DI],00h
  776. END;
  777.  
  778. {
  779.   function    : AllocEMS
  780.   parameters    : VAR handle:WORD; numpages:WORD
  781.   result    : BOOLEAN
  782.  
  783.   Allocates numpages (>0) of EMS-memory and returns the handle to it. If
  784.   succesfull this function will return TRUE. Otherwise, EMSErrorCode will
  785.   be set to a value indicating the error.
  786. }
  787. FUNCTION AllocEMS(VAR handle:WORD; numpages:WORD):BOOLEAN;ASSEMBLER;
  788. ASM
  789.     { allocate numpages of EMS-memory }
  790.     MOV    AH,43h
  791.     MOV    BX,[numpages]
  792.     INT    67h
  793.     MOV    [EMSErrorCode],AH
  794.     CMP    AH,00h
  795.     JNE    @Exit
  796.     { store handle }
  797.     LES    DI,handle
  798.     MOV    WORD PTR [DI],DX
  799.     MOV    AL,TRUE
  800.  
  801.     POP    BP
  802.     RET    TYPE handle + TYPE numpages
  803.  
  804. @Exit:    MOV    AL,FALSE
  805. END;
  806.  
  807. {
  808.   function    : FreeEMS
  809.   parameters    : VAR handle:WORD
  810.   result    : BOOLEAN
  811.  
  812.   Free's the EMS-memory allocated by AllocEMS. If succesfull this function
  813.   will return TRUE and the handle is no longer valid. Otherwise EMSError-
  814.   Code will be set to a value indiciting the error.
  815. }
  816. FUNCTION FreeEMS(VAR handle:WORD):BOOLEAN;ASSEMBLER;
  817. ASM
  818.     { free handle }
  819.     MOV    AH,45h
  820.     LES    DI,handle
  821.     MOV    DX,WORD PTR [DI]
  822.     INT    67h
  823.     MOV    [EMSErrorCode],AH
  824.     CMP    AH,00h
  825.     JNE    @Exit
  826.     MOV    AL,TRUE
  827.  
  828.     POP    BP
  829.     RET    TYPE handle
  830.  
  831. @Exit:    MOV    AL,FALSE
  832. END;
  833.  
  834. {
  835.   function    : MapEMS
  836.   parameters    : srcPage:WORD; destPage:BYTE; VAR handle:WORD
  837.   result    : BOOLEAN
  838.  
  839.   Maps destPage, belonging to the given handle, into physical accessible
  840.   base memory. Since the base-memory is divided in 4 pages of 16 kB each,
  841.   the value of destPage can only range from 0..3. The value of srcPage
  842.   can range form 0..n-1 where n is the total number of pages associated
  843.   with the given handle. This function will return TRUE if succesful or
  844.   FALSE in case of an error.
  845. }
  846. FUNCTION MapEMS(srcPage:WORD; destPage:BYTE; VAR handle:WORD):BOOLEAN;ASSEMBLER;
  847. ASM
  848.     { map scrPage -> destPage }
  849.     LES    DI,handle
  850.     MOV    DX,WORD PTR [DI]
  851.     MOV    BX,[srcPage]
  852.     MOV    AL,[destPage]
  853.     MOV    AH,44h
  854.     INT    67h
  855.     MOV    [EMSErrorCode],AH
  856.     CMP    AH,00h
  857.     JNE    @Exit
  858.     MOV    AL,TRUE
  859.  
  860.     POP    BP
  861.     RET    TYPE srcPage + TYPE destPage + TYPE handle
  862.  
  863. @Exit:    MOV    AL,FALSE
  864. END;
  865.  
  866. {
  867.   function    : EMSGetFreePages
  868.   parameters    : none
  869.   result    : WORD
  870.  
  871.   Returns the number of allocatable pages EMS-memory. This is equivalent
  872.   to the MemAvail-function for base-memory. If this function returns
  873.   zero, either an error has occured or there are allocatable pages left.
  874.   The user must verify this by checking the value of EMSErrorCode. If
  875.   succesful the value of EMSFreePages is updated.
  876. }
  877. FUNCTION EMSGetFreePages:WORD;ASSEMBLER;
  878. ASM
  879.     { obtain number of free pages }
  880.     MOV    AH,42h
  881.     INT    67h
  882.     MOV    [EMSErrorCode],AH
  883.     CMP    AH,00h
  884.     JNE    @Exit
  885.     MOV    [EMSFreePages],BX
  886.     MOV    AX,BX
  887.  
  888.     RET
  889.  
  890. @Exit:    XOR    AX,AX
  891. END;
  892.  
  893. {
  894.   function    : EMSGetHandlePages
  895.   parameters    : VAR handle:WORD
  896.   result    : WORD
  897.  
  898.   Returns the number of allocated pages associated with the given handle.
  899.   If this function returns zero, the user must check EMSErrorCode to
  900.   see if an error has occured. If no error occures and the function returns
  901.   zero, then the handle has no associated EMS-pages.
  902. }
  903. FUNCTION EMSGetHandlePages(VAR handle:WORD):WORD;ASSEMBLER;
  904. ASM
  905.     { obtain number of pages associated with handle }
  906.     MOV    AH,4Ch
  907.     LES    DI,handle
  908.     MOV    DX,WORD PTR [DI]
  909.     INT    67h
  910.     MOV    [EMSErrorCode],AH
  911.     CMP    AH,00h
  912.     JNE    @Exit
  913.     MOV    AX,BX
  914.  
  915.     POP    BP
  916.     RET    TYPE handle
  917.  
  918. @Exit:    XOR    AX,AX
  919. END;
  920.  
  921. {
  922.   ------------------------------------------------------------------------
  923.  
  924.         Implementation XMS Driver (XMS 3.0)
  925.  
  926.   ------------------------------------------------------------------------
  927. }
  928.  
  929. CONST
  930.   XMSControll        :POINTER=NIL;
  931.   XMS_HMAexist        :BOOLEAN=FALSE;
  932.  
  933. {
  934.   procedure    : InitXMS
  935.   parameters    : none
  936.   result    : none
  937.  
  938.   Initializes the XMS-driver. If XMS is available then the boolean XMSAvail
  939.   will be set to TRUE.
  940. }
  941. PROCEDURE InitXMS;ASSEMBLER;
  942. ASM
  943.     { check for XMS-driver }
  944.     MOV    AX,4300h
  945.     INT    2Fh
  946.     CMP    AL,80h
  947.     JE    @XMSfound
  948.  
  949.     RET
  950.  
  951. @XMSfound:
  952.     { request adress XMS-controll function }
  953.     MOV    AX,4310h
  954.     INT    2Fh
  955.     MOV    WORD PTR [XMSControll],BX
  956.     MOV    WORD PTR [XMSControll+2],ES
  957.  
  958.     { set global variable XMSAvail }
  959.     MOV    [XMSAvail],TRUE
  960. END;
  961.  
  962. {
  963.   procedure    : XMSGetVersion
  964.   parameters    : VAR num,dec:BYTE
  965.   result    : none
  966.  
  967.   Returns the XMS-drivers version number. The integer part is returned in
  968.   num, the decimal part in dec. If an error occures the number returned
  969.   will be zero and the user must check the value of XMSErrorCode
  970. }
  971. PROCEDURE XMSGetVersion(VAR num,dec:BYTE);ASSEMBLER;
  972. ASM
  973.     { no errors possible }
  974.     MOV    [XMSErrorCode],00h
  975.  
  976.     { request version number }
  977.     MOV    AH,00h
  978.     CALL    [XMSControll]
  979.     MOV    [XMS_HMAexist],DL
  980.  
  981.     { decode BCD-number }
  982.     MOV    BX,AX
  983.  
  984.     { decode decimal part }
  985.     MOV    AH,AL
  986.     AND    AH,0F0h
  987.     SHR    AH,2
  988.     MOV    CL,AH
  989.     SHR    AH,2
  990.     ADD    CL,AH
  991.     ADD    CL,AH
  992.     AND    AL,0Fh
  993.     ADD    CL,AL
  994.  
  995.     { decode integer part }
  996.     MOV    BL,BH
  997.     AND    BH,0F0h
  998.     SHR    BH,2
  999.     MOV    CH,BH
  1000.     SHR    BH,2
  1001.     ADD    CH,BH
  1002.     ADD    CH,BH
  1003.     AND    BL,0Fh
  1004.     ADD    CH,BL
  1005.  
  1006.     { store version number }
  1007.     LES    DI,num
  1008.     MOV    BYTE PTR [DI],CH
  1009.     LES    DI,dec
  1010.     MOV    BYTE PTR [DI],CL
  1011. END;
  1012.  
  1013. {
  1014.   function    : XMSGetMaxBlock
  1015.   parameters    : none
  1016.   result    : WORD
  1017.  
  1018.   Returns the maximum allocatable block of memory. If succesful the value
  1019.   of XMSFreeMemory and XMSMaxBlock is updated. Otherwise this funciotn
  1020.   returns zero. The amount returned is measured in Kb.
  1021. }
  1022. FUNCTION XMSGetMaxBlock:WORD;ASSEMBLER;
  1023. ASM
  1024.     { query free extended memory }
  1025.     MOV    AH,08h
  1026.     CALL    [XMSControll]
  1027.  
  1028.     { test for error }
  1029.     CMP    AX,0000h
  1030.     JE    @Error
  1031.  
  1032.     { update globals }
  1033.     MOV    [XMSFreeMemory],DX
  1034.     MOV    [XMSMaxBlock],AX
  1035.  
  1036.     RET
  1037.  
  1038. @Error:    MOV    [XMSErrorCode],BL
  1039. END;
  1040.  
  1041. {
  1042.   function    : AllocXMS
  1043.   parameters    : VAR handle:WORD; sizeKB:WORD
  1044.   returns    : BOOLEAN
  1045.  
  1046.   This function will try to allocate a XMS-block of sizeKB Kb. On succes
  1047.   the value of handle will be set to the newly acquired XMS-handle and the
  1048.   function will return TRUE. Otherwise, handle will be set to zero and the
  1049.   function returns FALSE.
  1050.  
  1051.   Note: XMS is allocated in chuncks of 16 Kb. So allocation 1 Kb means
  1052.     that the total free XMS decreases with 16 Kb
  1053. }
  1054. FUNCTION AllocXMS(VAR handle:WORD; sizeKB:WORD):BOOLEAN;ASSEMBLER;
  1055. ASM
  1056.     { load adress of handle }
  1057.     LES    DI,handle
  1058.  
  1059.     { request XMS-block }
  1060.     MOV    AH,09h
  1061.     MOV    DX,[sizeKB]
  1062.     CALL    [XMSControll]
  1063.  
  1064.     { test for error }
  1065.     CMP    AX,0000h
  1066.     JE    @Error
  1067.  
  1068.     { store handle and return TRUE }
  1069.     MOV    WORD PTR [DI],DX
  1070.     MOV    AL,TRUE
  1071.  
  1072.     POP    BP
  1073.     RET    TYPE handle + TYPE sizeKB
  1074.  
  1075. @Error: MOV    [XMSErrorCode],BL
  1076.     MOV    WORD PTR [DI],AX
  1077. END;
  1078.  
  1079. {
  1080.   function    : FreeXMS
  1081.   parameters    : VAR handle:WORD
  1082.   result    : BOOLEAN
  1083.  
  1084.   This function will free a previous allocated block of XMS-memory. It
  1085.   will return TRUE on succes or FALSE otherwise. If succesful the value
  1086.   of handle is no longer valid and will be set to zero!
  1087. }
  1088. FUNCTION FreeXMS(VAR handle:WORD):BOOLEAN;ASSEMBLER;
  1089. ASM
  1090.     { load adress of handle }
  1091.     LES    DI,handle
  1092.  
  1093.     { free XMS-block }
  1094.     MOV    AH,0Ah
  1095.     MOV    DX,WORD PTR [DI]
  1096.     CALL    [XMSControll]
  1097.  
  1098.     { test for error }
  1099.     CMP    AX,0000h
  1100.     JE    @Error
  1101.  
  1102.     { set handle to zero and return TRUE }
  1103.     MOV    WORD PTR [DI],0000h
  1104.     MOV    AL,TRUE
  1105.  
  1106.     POP    BP
  1107.     RET    TYPE handle
  1108.  
  1109. @Error: MOV    [XMSErrorCode],BL
  1110. END;
  1111.  
  1112. {
  1113.   function    : MoveXMS
  1114.   parameters    : VAR mvData:XMSMoveStruct
  1115.   result    : BOOLEAN
  1116.  
  1117.   This function will move the contents of an XMS-handle to another area
  1118.   in memory. The function will return TRUE on succes of FALSE otherwise.
  1119.  
  1120.   The parameter mvData of type XMSMoveStruct contains the information
  1121.   needed for the move.
  1122.  
  1123.   mvData.length        32-bit number of bytes to transfer
  1124.   mvData.hSource    XMS-handle of source-block
  1125.   mvData.offsetSource    32-bit offset into the source-block
  1126.   mvData.hDest        XMS-handle of dest-block
  1127.   mvData.offsetDest    32-bit offset into the dest-block
  1128.  
  1129.   Note: if hSource of hDest is set to 0000h then the corresponding 32-bit
  1130.     offset is interpreted as a segment:offset adress into real-mode
  1131.     accesible memory (up to 1 Mb)
  1132. }
  1133. FUNCTION MoveXMS(VAR mvData:XMSMoveStruct):BOOLEAN;ASSEMBLER;
  1134. ASM
  1135.     { load mvData }
  1136.     LDS    SI,mvData
  1137.     MOV    AH,0Bh
  1138.     CALL    [XMSControll]
  1139.  
  1140.     { test for error }
  1141.     CMP    AX,0000h
  1142.     JE    @Error
  1143.  
  1144.     POP    BP
  1145.     RET    TYPE mvData
  1146.  
  1147. @Error: MOV    [XMSErrorCode],BL
  1148. END;
  1149.  
  1150. {
  1151.   function    : ReAllocXMS
  1152.   parameters    : VAR handle:WORD; newsizeKB:WORD
  1153.   result    : BOOLEAN
  1154.  
  1155.   This function will try to reallocate the XMS-block so that it's size
  1156.   will become newsizeKB. If the new block is smaller than the old one,
  1157.   all data at the upper end of the block are lost. The function will
  1158.   return TRUE on succes or FALSE otherwise.
  1159. }
  1160. FUNCTION ReAllocXMS(VAR handle:WORD; newsizeKB:WORD):BOOLEAN;ASSEMBLER;
  1161. ASM
  1162.     { load handle }
  1163.     LES    DI,handle
  1164.     MOV    DX,WORD PTR [DI]
  1165.     MOV    AH,0Fh
  1166.     CALL    [XMSControll]
  1167.  
  1168.     { test for error }
  1169.     CMP    AX,0000h
  1170.     JE    @Error
  1171.  
  1172.     POP    BP
  1173.     RET    TYPE handle + TYPE newsizeKB
  1174.  
  1175. @Error:    MOV    [XMSErrorCode],BL
  1176. END;
  1177.  
  1178. {
  1179.   function    : XMSGetBlockSize
  1180.   parameters    : VAR handle:WORD
  1181.   result    : WORD
  1182.  
  1183.   This function will return the size in Kb of the allocated XMS-block
  1184.   corresponding to the given handle. It will return zero in case of an
  1185.   error (since no XMS-block of zero Kb can be allocated).
  1186. }
  1187. FUNCTION XMSGetBlockSize(VAR handle:WORD):WORD;ASSEMBLER;
  1188. ASM
  1189.     { load handle }
  1190.     LES    DI,handle
  1191.  
  1192.     { request block information }
  1193.     MOV    AH,0Fh
  1194.     MOV    DX,WORD PTR [DI]
  1195.     CALL    [XMSControll]
  1196.  
  1197.     { test for error }
  1198.     CMP    AX,0000h
  1199.     JE    @Error
  1200.  
  1201.     { return size XMS-block in Kb }
  1202.     MOV    AX,DX
  1203.  
  1204.     POP    BP
  1205.     RET    TYPE handle
  1206.  
  1207. @Error: MOV    [XMSErrorCode],BL
  1208. END;
  1209.  
  1210. VAR
  1211.   mvData    :XMSMoveStruct;
  1212.  
  1213. {
  1214.   procedure    : RealToXMS
  1215.   parameters    : VAR source; VAR hDest:WORD; ofs,cnt:LONGINT
  1216.   result    : none
  1217.  
  1218.   Moves cnt bytes from source in real memory to XMS-memory corresponding
  1219.   to the handle hDest. The data will be written in XMS-memory starting
  1220.   from offset ofs.
  1221. }
  1222. PROCEDURE RealToXMS(VAR source; VAR hDest:WORD; ofs,cnt:LONGINT);ASSEMBLER;
  1223. ASM
  1224.     PUSH    DS
  1225.  
  1226.     { fill XMSMoveStruct }
  1227.     MOV    AX,WORD [cnt]
  1228.     MOV    DX,WORD [cnt+2]
  1229.     MOV    WORD [mvData.length],AX
  1230.     MOV    WORD [mvData.length+2],DX
  1231.  
  1232.     MOV    WORD [mvData.hSource],0000h
  1233.     MOV    AX,WORD [source]
  1234.     MOV    DX,WORD [source+2]
  1235.     MOV    WORD [mvData.offsetSource],AX
  1236.     MOV    WORD [mvData.offsetSource+2],DX
  1237.  
  1238.     LES    DI,hDest
  1239.     MOV    AX,WORD PTR [DI]
  1240.     MOV    WORD [mvData.hDest],AX
  1241.     MOV    AX,WORD [ofs]
  1242.     MOV    DX,WORD [ofs+2]
  1243.     MOV    WORD [mvData.offsetDest],AX
  1244.     MOV    WORD [mvData.offsetDest+2],DX
  1245.  
  1246.     { load XMSMoveStruct }
  1247.     LEA    SI,XMSMoveStruct PTR mvData
  1248.     MOV    AH,0Bh
  1249.     CALL    [XMSControll]
  1250.  
  1251.     { test for error }
  1252.     CMP    AX,0000h
  1253.     JE    @Error
  1254.  
  1255.     POP    DS
  1256.  
  1257.     MOV    SP,BP
  1258.     POP    BP
  1259.     RET    TYPE source + TYPE hDest + TYPE ofs + TYPE cnt
  1260.  
  1261. @Error:    MOV    [XMSErrorCode],BL
  1262.  
  1263.     POP    DS
  1264. END;
  1265.  
  1266. {
  1267.   procedure    : XMSToReal
  1268.   parameters    : VAR hSource:WORD; ofs:LONGINT; VAR dest; cnt:LONGINT
  1269.   result    : none
  1270.  
  1271.   Moves cnt bytes from XMS-memory corresponding to the handle hSource
  1272.   starting at offset ofs to source in real memory.
  1273. }
  1274. PROCEDURE XMSToReal(VAR hSource:WORD; ofs:LONGINT; VAR dest; cnt:LONGINT);ASSEMBLER;
  1275. ASM
  1276.     PUSH    DS
  1277.  
  1278.     { fill XMSMoveStruct }
  1279.     MOV    AX,WORD [cnt]
  1280.     MOV    DX,WORD [cnt+2]
  1281.     MOV    WORD [mvData.length],AX
  1282.     MOV    WORD [mvData.length+2],DX
  1283.  
  1284.     MOV    WORD [mvData.hDest],0000h
  1285.     MOV    AX,WORD [dest]
  1286.     MOV    DX,WORD [dest+2]
  1287.     MOV    WORD [mvData.offsetDest],AX
  1288.     MOV    WORD [mvData.offsetDest+2],DX
  1289.  
  1290.     LES    DI,hSource
  1291.     MOV    AX,WORD PTR [DI]
  1292.     MOV    WORD [mvData.hSource],AX
  1293.     MOV    AX,WORD [ofs]
  1294.     MOV    DX,WORD [ofs+2]
  1295.     MOV    WORD [mvData.offsetSource],AX
  1296.     MOV    WORD [mvData.offsetSource+2],DX
  1297.  
  1298.     { load XMSMoveStruct }
  1299.     LEA    SI,XMSMoveStruct PTR mvData
  1300.     MOV    AH,0Bh
  1301.     CALL    [XMSControll]
  1302.  
  1303.     { test for error }
  1304.     CMP    AX,0000h
  1305.     JE    @Error
  1306.  
  1307.     POP    DS
  1308.  
  1309.     POP    BP
  1310.     RET    TYPE hSource + TYPE ofs + TYPE dest + TYPE cnt
  1311.  
  1312. @Error:    MOV    [XMSErrorCode],BL
  1313.  
  1314.     POP    DS
  1315. END;
  1316.  
  1317. END.